package cn.hyatt.auth.service.impl;

import cn.hyatt.auth.dto.systemDept.SystemDeptFindDto;
import cn.hyatt.auth.dto.systemDept.SystemDeptSaveDto;
import cn.hyatt.auth.dto.systemDept.SystemDeptUpdateDto;
import cn.hyatt.auth.dto.systemDept.SystemDeptVo;
import cn.hyatt.auth.entity.SystemDept;
import cn.hyatt.auth.event.SystemDeptEvent;
import cn.hyatt.auth.mapper.SystemDeptMapper;
import cn.hyatt.auth.service.SystemDeptService;
import cn.hyatt.common.exception.BusinessException;
import cn.hyatt.common.utils.ValidationUtil;
import cn.hyatt.core.utils.PageUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * 系统部门-服务实现
 *
 * @author hyatt
 */
@Slf4j
@Service
@Primary
@AllArgsConstructor
public class SystemDeptServiceImpl extends ServiceImpl<SystemDeptMapper, SystemDept> implements SystemDeptService {

    private ApplicationEventPublisher publisher;

    @Override
    public List<SystemDept> findByList(SystemDeptFindDto dto) {
        return baseMapper.findByList(dto);
    }

    @Override
    public IPage<SystemDept> findByPage(SystemDeptFindDto dto) {
        return baseMapper.findByPage(PageUtil.page(dto), dto);
    }

    @Override
    @Transactional
    public void save(SystemDeptSaveDto dto) {
        // Copy 属性
        SystemDept entity = new SystemDept();
        BeanUtils.copyProperties(dto, entity);

        if (dto.getParentId() != null) {
            SystemDept parentDept = getById(dto.getParentId());
            entity.setAncestors(parentDept.getAncestors() + parentDept.getId() + ",");
        }

        // 验证数据内容
        ValidationUtil.validate(entity);
        // 插入数据
        baseMapper.insert(entity);

        // 发布事件
        publisher.publishEvent(new SystemDeptEvent.Save(entity));
    }

    @Override
    @Transactional
    public void update(Long id, SystemDeptUpdateDto dto) {
        // 获取修改对象
        Optional<SystemDept> optional = getOptById(id);
        SystemDept entity = optional.orElseThrow(
                () -> new BusinessException("找不到Id为(" + id + ")的数据")
        );
        // 保留旧实体记录
        SystemDept oldEntity = new SystemDept();
        BeanUtils.copyProperties(entity, oldEntity);
        // Copy 属性
        BeanUtils.copyProperties(dto, entity);
        if (dto.getParentId() != null) {
            SystemDept parentDept = getById(dto.getParentId());
            entity.setAncestors(parentDept.getAncestors() + parentDept.getId() + ",");
        }
        // 验证数据内容
        ValidationUtil.validate(entity);
        // 按Id更新
        baseMapper.updateById(entity);

        if (dto.getParentId() != null) {
            updateChildrenAncestors(entity);
        }

        // 发布事件
        publisher.publishEvent(new SystemDeptEvent.Update(oldEntity, entity));
    }

    /**
     * 更新子祖先
     *
     * @param entity 父
     */
    public void updateChildrenAncestors(SystemDept entity) {
        SystemDeptFindDto dto = new SystemDeptFindDto();
        dto.setParentId(entity.getParentId());
        List<SystemDept> childrenList = baseMapper.findByList(dto);
        childrenList.forEach(it -> {
            it.setAncestors(entity.getAncestors() + entity.getId() + ",");
            baseMapper.updateById(it);
            updateChildrenAncestors(it);
        });
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        // 按Id删除
        baseMapper.deleteById(id);
        // 发布事件
        publisher.publishEvent(new SystemDeptEvent.Delete(id));
    }

    @Override
    public SystemDeptVo toVo(SystemDept entity) {
        // Copy 属性
        SystemDeptVo vo = new SystemDeptVo();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }
}
